// ==UserScript==
// @name         公众号发表记录统计助手 V1.0.1
// @namespace    https://mp.weixin.qq.com/
// @version      2024-12-09
// @description  方便统计获取发表记录以及阅读量等数据
// @author       work@lcc.me
// @match        https://mp.weixin.qq.com/*
// @icon         https://s21.ax1x.com/2024/03/21/pFflilV.png
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // 缓存统计的数据
    var appmsgpublish = [];
    // 表头配置，包含列宽、排序和隐藏信息
    var headersConfig = [
        {col_name: "primaryKey", display: "数据主键", order: 0, width: "100px", hidden: true},
        {col_name: "timeText", display: "发布时间", order: 1, width: "70px", hidden: false},
        {col_name: "statusText", display: "发布状态", order: 2, width: "55px", hidden: false},
        {col_name: "imageUrl", display: "封面图片", order: 3, width: "80px", hidden: true},
        {col_name: "titleText", display: "文章标题", order: 4, width: "300px", hidden: false},
        {col_name: "chatCount", display: "留言人数", order: 9, width: "50px", hidden: false},
        {col_name: "lineCount", display: "划线人数", order: 10, width: "50px", hidden: false},
        {col_name: "readingCount", display: "阅读人数", order: 5, width: "50px", hidden: false},
        {col_name: "likeCount", display: "点赞人数", order: 6, width: "50px", hidden: false},
        {col_name: "shareCount", display: "转发人数", order: 7, width: "50px", hidden: false},
        {col_name: "watchingCount", display: "在看人数", order: 8, width: "50px", hidden: false}
    ];

    // -------------------[Function Handle]-----------------------------  //
    // 通过星期*获取日期
    function getDateStringFromWeekday(input) {
        // 正则表达式匹配包含“星期”的星期信息
        const weekdayRegex = /星期[一二三四五六日]/;
        const match = input.match(weekdayRegex);

        // 如果输入字符串中没有匹配到星期信息，抛出错误
        if (!match) {
            return input;
        }

        // 提取星期信息
        const inputWeekday = match[0];

        // 获取当前日期
        const today = new Date();

        // 将输入的星期字符串转换为数字，星期一为0，星期日为6
        const weekdayMap = {
            '星期一': 0,
            '星期二': 1,
            '星期三': 2,
            '星期四': 3,
            '星期五': 4,
            '星期六': 5,
            '星期日': 6
        };

        // 获取当前星期的数字表示
        let todayWeekdayNum = weekdayMap[today.toLocaleDateString('zh-CN', { weekday: 'long' })];

        // 获取输入星期的数字表示
        let inputWeekdayNum = weekdayMap[inputWeekday];

        // 计算需要偏移的天数
        let offset = inputWeekdayNum - todayWeekdayNum;

        // 如果输入的星期在当前星期之前，偏移量需要减去7（一周的天数），以得到上一个星期的对应日期
        if (offset > 0) {
            offset -= 7;
        }

        // 创建一个新的日期对象，偏移相应的天数
        const targetDate = new Date(today);
        targetDate.setDate(today.getDate() + offset);

        // 格式化日期为 yyyy-MM-dd
        const yyyy = targetDate.getFullYear();
        const MM = (targetDate.getMonth() + 1).toString().padStart(2, '0');
        const dd = targetDate.getDate().toString().padStart(2, '0');
        return `${yyyy}-${MM}-${dd}`;
    }

    // 定义一个函数来转换日期格式
    function handleDate(text) {
        // 如果时间文本中包含“今天”，则转换为今天的日期
        if (text.includes('今天')) {
            return new Date().toISOString().split('T')[0];
        }
        // 如果时间文本中包含“昨天”，则转换为昨天的日期
        if (text.includes('昨天')) {
            var yesterday = new Date();
            yesterday.setDate(yesterday.getDate() - 1);
            return yesterday.toISOString().split('T')[0];
        }

        if(text.includes('星期')){
            return getDateStringFromWeekday(text);
        }

        // 检查时间文本中是否包含年份，如果不包含则追加当前年份
        if (!/\d{4}/.test(text)) {
            return '2024年' + text;
        }
        return text; // 如果不需要转换，直接返回原始文本
    }

    // 加载Excel插件，用于数据导出
    async function loadXLSXLibrary() {
        var script = document.createElement('script');
        script.src = "https://unpkg.com/xlsx/dist/xlsx.full.min.js";
        script.onload = function() {
            // 脚本加载完成后，XLSX库应该已经可用
            // 你可以在这里调用XLSX库的方法
            console.log('XLSX library loaded successfully');
        };
        script.onerror = function() {
            // 处理加载失败的情况
            console.error('Failed to load XLSX library');
        };
        document.head.appendChild(script);
    }

    // 打开展示面板
    function openPanel(){
        var modal = document.getElementById('cc_modal_div');
        var overlay = document.getElementById('cc_overlay_div');

        // 防止重复生成
        if(!modal){
            // 创建遮罩层
            overlay = document.createElement('div');
            overlay.id = 'cc_overlay_div';
            overlay.style.position = 'fixed';
            overlay.style.left = '0';
            overlay.style.top = '0';
            overlay.style.width = '100%';
            overlay.style.height = '100%';
            overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
            overlay.style.zIndex = '999';
            overlay.style.cursor = 'pointer';
            document.body.appendChild(overlay);

            // 创建弹出层的主体
            modal = document.createElement('div');
            modal.id = 'cc_modal_div';
            modal.style.position = 'fixed';
            modal.style.left = '50%';
            modal.style.top = '50%';
            modal.style.transform = 'translate(-50%, -50%)';
            modal.style.width = '1000px';
            modal.style.height = '800px';
            modal.style.backgroundColor = '#fff';
            modal.style.zIndex = '1000';
            modal.style.border = '1px solid #000';
            modal.style.padding = '20px';
            document.body.appendChild(modal);

            openPanel2Header(modal,overlay);
            openPanel2ToolsBar(modal);
            openPanel2StatArea(modal);
            openPanel2ContentArea(modal);

            // 添加事件监听器，点击遮罩层或关闭按钮时关闭弹出层
            overlay.addEventListener('click', function() {
                overlay.style.display = 'none';
                modal.style.display = 'none';
            });
        }

        // 显示弹出层
        overlay.style.display = 'block';
        modal.style.display = 'block';
    }
    // 创建标题栏
    function openPanel2Header(modal,overlay){
        // 创建标题栏
        var titleBar = document.createElement('div');
        titleBar.style.position = 'relative';
        titleBar.style.height = '40px';
        titleBar.style.lineHeight = '40px';
        titleBar.style.backgroundColor = '#333';
        titleBar.style.color = '#fff';
        titleBar.style.padding = '0 20px';
        titleBar.style.textAlign = 'center';
        titleBar.textContent = '文章信息预览';
        modal.appendChild(titleBar);

        // 创建关闭按钮
        var closeButton = document.createElement('button');
        closeButton.style.position = 'absolute';
        closeButton.style.right = '10px';
        closeButton.style.top = '0';
        closeButton.style.height = '40px';
        closeButton.style.lineHeight = '40px';
        closeButton.style.padding = '0 20px';
        closeButton.style.backgroundColor = '#333';
        closeButton.style.color = '#fff';
        closeButton.textContent = '关闭';
        titleBar.appendChild(closeButton);

        closeButton.addEventListener('click', function() {
            overlay.style.display = 'none';
            modal.style.display = 'none';
        });
    }
    // 创建按钮区域
    function openPanel2ToolsBar(modal){
        // 创建按钮区域
        var buttonArea = document.createElement('div');
        buttonArea.style.position = 'relative';
        buttonArea.style.height = '40px';
        buttonArea.style.display = 'flex'; // 使用flex布局以水平排列按钮
        buttonArea.style.alignItems = 'center'; // 垂直居中

        // 创建开始日期输入框
        var startDateInput = document.createElement('input');
        startDateInput.type = 'date';
        startDateInput.style.height = '26px';
        startDateInput.id = 'cc_query_start_date';
        startDateInput.title = '开始日期';
        startDateInput.style.marginRight = '10px'; // 增加右边距

        // 创建结束日期输入框
        var endDateInput = document.createElement('input');
        endDateInput.type = 'date';
        endDateInput.style.height = '26px';
        endDateInput.id = 'cc_query_end_date';
        endDateInput.title = '结束日期';
        endDateInput.style.marginRight = '10px'; // 增加右边距

        // 将开始日期和结束日期输入框添加到日期输入区域
        buttonArea.appendChild(startDateInput);
        buttonArea.appendChild(endDateInput);

        // 创建复选框
        var checkbox = document.createElement('input');
        checkbox.type = 'checkbox';
        checkbox.id = 'cc_query_checkbox'; // 给复选框设置一个ID
        checkbox.title = '选中后排除已删除的文章';
        checkbox.style.marginRight = '5px'; // 增加右边距

        // 创建标签
        var label = document.createElement('label');
        label.htmlFor = 'cc_query_checkbox'; // 将标签的htmlFor属性设置为复选框的ID，以关联复选框和标签
        label.textContent = '不看已删除'; // 设置标签的文字
        label.title = '选中后排除已删除的文章';
        label.style.marginRight = '10px'; // 增加右边距

        // 将复选框和标签添加到按钮区域
        buttonArea.appendChild(checkbox);
        buttonArea.appendChild(label);

        // 创建搜索按钮
        var queryButton = document.createElement('button');
        queryButton.id = 'cc_query_button';
        queryButton.style.height = '30px';
        queryButton.style.lineHeight = '30px';
        queryButton.style.padding = '0 20px';
        queryButton.style.backgroundColor = '#f0a1a8'; // 设置按钮背景颜色
        queryButton.style.color = '#fff'; // 设置按钮文本颜色
        queryButton.style.border = 'none'; // 移除边框
        queryButton.style.borderRadius = '4px'; // 设置圆角
        queryButton.style.cursor = 'pointer'; // 设置鼠标悬停时的指针样式
        queryButton.style.marginRight = '10px'; // 增加右边距
        queryButton.textContent = '筛选数据';
        // 创建下载数据按钮
        var downloadButton = document.createElement('button');
        downloadButton.id = 'cc_download_button';
        downloadButton.style.height = '30px';
        downloadButton.style.lineHeight = '30px';
        downloadButton.style.padding = '0 20px';
        downloadButton.style.backgroundColor = '#5cb85c'; // 设置按钮背景颜色
        downloadButton.style.color = '#fff'; // 设置按钮文本颜色
        downloadButton.style.border = 'none'; // 移除边框
        downloadButton.style.borderRadius = '4px'; // 设置圆角
        downloadButton.style.cursor = 'pointer'; // 设置鼠标悬停时的指针样式
        downloadButton.textContent = '下载数据';

        // 将下载数据按钮添加到按钮区域
        buttonArea.appendChild(queryButton);
        // 将下载数据按钮添加到按钮区域
        buttonArea.appendChild(downloadButton);

        // 将按钮区域添加到模态框中
        modal.appendChild(buttonArea);

        queryButton.addEventListener('click', async function() {
            const startDate = document.getElementById('cc_query_start_date').value;
            const endDate = document.getElementById('cc_query_end_date').value;

            // 将字符串转换为日期对象
            const parseDate = (dateStr) => dateStr ? new Date(dateStr) : null;

            // 定义筛选函数
            const filterFunc = (item) => {
                const itemDate = new Date(item.timeText);
                if(document.getElementById('cc_query_checkbox').checked && item.statusText == '已删除'){
                    return false;
                }

                // 根据开始日期和结束日期的存在性进行不同的比较
                if (startDate && endDate) {
                    // 如果开始日期和结束日期都不为空，则进行等于大于和等于小于的限制
                    return itemDate >= parseDate(startDate) && itemDate <= parseDate(endDate);
                } else if (startDate) {
                    // 如果开始日期不为空，则开始不做限制
                    return itemDate >= parseDate(startDate);
                } else if (endDate) {
                    // 如果结束日期不为空，则结束不做限制
                    return itemDate <= parseDate(endDate);
                } else {
                    // 如果开始日期和结束日期都为空，则不过滤
                    return true;
                }
            };

            // 使用 filter 方法进行数据筛选
            renderDataHandle(appmsgpublish.filter(filterFunc));
        });
        downloadButton.addEventListener('click', async function() {
            const table = document.getElementById('cc_data_table');
            const filename = 'Wechat_appmsgpublish.xlsx';
            if (table) {
                const workbook = window.XLSX.utils.table_to_book(table);
                window.XLSX.writeFile(workbook, filename);
            } else {
                console.error('Table not found');
            }
        });
    }

    // 创建统计区域
    function openPanel2StatArea(modal){
        // 创建按钮区域
        var statArea = document.createElement('div');
        statArea.style.position = 'relative';
        statArea.style.height = '40px';
        statArea.style.display = 'flex'; // 使用flex布局以水平排列按钮
        statArea.style.alignItems = 'center'; // 垂直居中
        statArea.style.color = '#fb8b05';


        // 创建span元素来显示统计结果
        var statsSpan = document.createElement('span');
        statsSpan.id = 'cc_show_number';

        statArea.appendChild(statsSpan);


        // 将按钮区域添加到模态框中
        modal.appendChild(statArea);
    }
    // 创建内容区域
    function openPanel2ContentArea(modal){
        // 创建内容区域
        var contentArea = document.createElement('div');
        contentArea.style.height = 'calc(100% - 130px)';
        contentArea.style.overflow = 'auto'; // 如果内容超出高度，显示滚动条
        modal.appendChild(contentArea);

        // 根据 order 属性对 headersConfig 进行排序
        headersConfig.sort(function(a, b) {
            return a.order - b.order;
        });

        // 创建表格
        var table = document.createElement('table');
        table.id = 'cc_data_table';
        table.style.width = '100%';
        table.style.borderCollapse = 'collapse';
        table.style.tableLayout = 'fixed';

        // 创建表头
        var thead = document.createElement('thead');
        var headerRow = document.createElement('tr');
        headersConfig.forEach(function(header) {
            if (!header.hidden) { // 检查是否隐藏
                var headerCell = document.createElement('th');
                headerCell.textContent = header.display;
                headerCell.style.border = '1px solid #ddd';
                headerCell.style.padding = '8px';
                headerCell.style.width = header.width;
                headerRow.appendChild(headerCell);
            }
        });
        thead.appendChild(headerRow);
        table.appendChild(thead);

        // 创建表体
        var tbody = document.createElement('tbody');
        tbody.id = 'cc_data_table_tbody';
        table.appendChild(tbody);

        // 将表格添加到contentArea中
        contentArea.appendChild(table);
    }

    // 初始化查看结果按钮
    function initShowPanelButton(originalDiv){
        // 克隆原始的div元素
        var clonedDiv = originalDiv.cloneNode(true);
        clonedDiv.id = 'cc_show_button';

        // 修改克隆出来的div元素中的按钮名称
        var clonedButton = clonedDiv.querySelector('button');
        clonedButton.textContent = '展示数据';
        clonedButton.style.color = '#ffffff';
        clonedButton.style.backgroundColor = '#2486b9';

        // 将修改后的克隆div元素追加到原始div元素的后面
        originalDiv.parentNode.insertBefore(clonedDiv, originalDiv.nextSibling);

        clonedDiv.addEventListener('click', function() {
            if (appmsgpublish.length === 0) {
                appmsgpublish = Object.keys(localStorage).filter(key => key.startsWith('__CC__Article__')).sort((a, b) => a.localeCompare(b)).map(key => JSON.parse(localStorage.getItem(key)));
            }
            // console.info(appmsgpublish);
            openPanel();
            renderDataHandle(appmsgpublish);
        });
    }

    // 渲染提取到的数据
    function renderDataHandle(data){
        const stats = data.reduce((acc, item) => {
            // 定义一个函数来安全地解析整数
            const parseInteger = (value) => {
                const number = parseInt(value ? value.replace(/,/g, '') : 0, 10);
                return isNaN(number) ? 0 : number;
            };

            // 使用 parseInteger 函数来累加每个属性的值
            acc.chatCount += parseInteger(item.chatCount);
            acc.lineCount += parseInteger(item.lineCount);
            acc.readingCount += parseInteger(item.readingCount);
            acc.likeCount += parseInteger(item.likeCount);
            acc.shareCount += parseInteger(item.shareCount);
            acc.watchingCount += parseInteger(item.watchingCount);
            return acc;
        }, { chatCount: 0, lineCount: 0, readingCount: 0, likeCount: 0, shareCount: 0, watchingCount: 0 });

        // console.log("数据统计结果",stats);

        document.getElementById('cc_show_number').innerHTML = `数据统计信息>> 阅读人数: ${stats.readingCount}, 点赞人数: ${stats.likeCount}, 转发人数: ${stats.shareCount}, 在看人数: ${stats.watchingCount}, 留言人数: ${stats.chatCount}, 划线人数: ${stats.lineCount}`;

        var tbody = document.getElementById('cc_data_table_tbody');
        tbody.innerHTML = '';

        data.forEach(function(row) {
            var dataRow = document.createElement('tr');
            headersConfig.forEach(function(header) {
                if (!header.hidden) { // 检查是否隐藏
                    var cell = document.createElement('td');
                    cell.style.border = '1px solid #ddd';
                    cell.style.padding = '8px';
                    cell.style.width = header.width;
                    if (header.col_name === "imageUrl") {
                        var img = document.createElement('img');
                        img.src = row[header.col_name];
                        img.style.width = '80px'; // 设置图片宽度
                        img.style.height = '60px'; // 设置图片高度
                        img.style.objectFit = 'cover'; // 确保图片不失真
                        // 使图片居中
                        var div = document.createElement('div');
                        div.style.display = 'flex';
                        div.style.justifyContent = 'center';
                        div.style.alignItems = 'center';
                        div.style.width = '100%'; // 确保div占满整个单元格宽度
                        div.style.height = '100%'; // 确保div占满整个单元格高度
                        div.appendChild(img);
                        cell.appendChild(div);
                    } else {
                        cell.textContent = row[header.col_name];
                    }
                    dataRow.appendChild(cell);
                }
            });
            tbody.appendChild(dataRow);
        });
    }

    // -------------------[Function Body]-----------------------------  //
    // 加载Excel插件
    loadXLSXLibrary();

    // 1. 找到原始的div元素
    var originalDiv = document.querySelectorAll('.weui-desktop-btn_wrp')[3];

    // 2. 判断是否找到了原始的div元素
    if (originalDiv) {
        // 克隆原始的div元素
        var clonedDiv = originalDiv.cloneNode(true);
        clonedDiv.id = 'cc_task_button';

        // 修改克隆出来的div元素中的按钮名称
        var clonedButton = clonedDiv.querySelector('button');
        clonedButton.textContent = '开始统计';
        clonedButton.style.color = '#ffffff';
        clonedButton.style.backgroundColor = '#f86b1d';

        // 将修改后的克隆div元素追加到原始div元素的后面
        originalDiv.parentNode.insertBefore(clonedDiv, originalDiv.nextSibling);

        // 初始化展示结果按钮
        initShowPanelButton(clonedDiv);

        // 给克隆的div元素绑定单击事件
        clonedDiv.addEventListener('click', function() {
            // 开启任务
            sessionStorage.setItem('__CC__Article__Task__OPEN__', true)
            // 将页面滚动到底部
            window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' });

            // 当前是第几页
            var pagenum = document.querySelector('.weui-desktop-pagination__num.weui-desktop-pagination__num_current').textContent;
            console.info(`当前是${pagenum}页`);

            var panels = document.querySelectorAll('.weui-desktop-block');

            panels.forEach((panel, pidx)=>{
                // 获取当前元素中class为weui-desktop-mass__time的子元素的文本
                var timeElement = panel.querySelector('.weui-desktop-mass__time');
                var statusTextElement = panel.querySelector('.weui-desktop-mass__status_text');
                if (!timeElement || !statusTextElement) {
                    return;
                }

                var timeText = timeElement.textContent;
                var statusText = statusTextElement.textContent;

                // 使用定义的函数处理日期
                timeText = handleDate(timeText).replace(/年|月/g, '-').replace(/日/g, '');

                // 获取所有具有样式publish_hover_content的元素
                var elements = panel.querySelectorAll('.publish_hover_content');

                // 循环遍历所有找到的元素
                elements.forEach(function(element, nidx) {
                    // 1. 获取样式weui-desktop-mass-appmsg__thumb的背景图片地址
                    var thumbStyle = element.querySelector('.weui-desktop-mass-appmsg__thumb').style;
                    var backgroundImage = thumbStyle.backgroundImage;
                    var imageUrl = backgroundImage ? backgroundImage.slice(5, -2) : '无背景图片'; // 去掉url(")并提取地址

                    // 2. 获取样式weui-desktop-mass-appmsg__title的文本
                    var titleText = element.querySelector('.weui-desktop-mass-appmsg__title').textContent;

                    // 3. 获取样式weui-desktop-mass-media__data__inner的所有文本
                    var dataInnerElements = element.querySelectorAll('.weui-desktop-mass-media__data__inner');

                    // 分别将阅读人数、点赞人数、转发人数、在看人数赋值给对应的变量
                    var readingCount = dataInnerElements[0].textContent; // 阅读人数
                    var likeCount = dataInnerElements[1].textContent; // 点赞人数
                    var shareCount = dataInnerElements[2].textContent; // 转发人数
                    var watchingCount = dataInnerElements[3].textContent; // 在看人数
                    var chatCount = 0; // 留言人数
                    var lineCount = 0; // 划线人数
                    if(dataInnerElements.length == 6){
                        chatCount = dataInnerElements[4].textContent; // 留言人数
                        lineCount = dataInnerElements[5].textContent; // 划线人数
                    }else if(dataInnerElements.length == 6){
                        lineCount = dataInnerElements[4].textContent; // 划线人数
                    }

                    // 组装数据主键
                    var primaryKey = ((100+(+pagenum))+''+(pidx.toString().padStart(2, '0'))+(nidx.toString().padStart(3, '0')))

                    var articleObject = {
                        primaryKey: primaryKey, // 数据主键
                        timeText: timeText, // 发布时间
                        statusText: statusText, // 发布状态
                        imageUrl: imageUrl, // 背景图片
                        titleText: titleText, // 文章标题
                        chatCount: chatCount, // 留言人数
                        lineCount: lineCount, // 划线人数
                        readingCount: readingCount, // 阅读人数
                        likeCount: likeCount, // 点赞人数
                        shareCount: shareCount, // 转发人数
                        watchingCount: watchingCount // 在看人数
                    };

                    // 将对象转换为JSON字符串
                    var articleJson = JSON.stringify(articleObject);

                    // 存储到localStorage中，键为数据主键
                    localStorage.setItem(`__CC__Article__${primaryKey}`, articleJson);

                    console.log(primaryKey,articleObject);
                    console.log('---------------------------------------------------');
                });
            });

            // 获取“下一页”按钮对象
            var nextPageButtons = document.querySelectorAll('.weui-desktop-btn.weui-desktop-btn_default.weui-desktop-btn_mini');
            //
            var nextPageButton = nextPageButtons[nextPageButtons.length == 1 ? 0 : 1];

            // 检查是否找到了按钮
            if (nextPageButton && nextPageButton.textContent == '下一页') {
                // 模拟点击事件
                nextPageButton.click();
            } else {
                // 已经到底，移除任务
                sessionStorage.removeItem('__CC__Article__Task__OPEN__');
                document.getElementById('cc_show_button').click();
                console.log('未找到“下一页”按钮');
            }
        });

        var isOpen = sessionStorage.getItem('__CC__Article__Task__OPEN__');
        if(isOpen){
            setTimeout(()=>{
                // 根据ID获取元素
                var button = document.getElementById('cc_task_button');

                // 检查元素是否存在
                if (button) {
                    // 触发click事件
                    button.click();
                } else {
                    console.log('未找到ID为 "cc_task_button" 的元素');
                }
            },2000);
        }
    } else {
        // 如果找不到原始的div元素，则不执行任何操作
        console.log('未找到指定的div元素');
    }

})();